package org.xqh.utils.encrypt;

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StopWatch;
import org.springframework.util.StringUtils;

import javax.crypto.Cipher;
import java.math.BigInteger;
import java.security.*;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;

/**
 * @ClassName RSAUtils
 * @Description 非对称加密算法
 * @Author xuqianghui
 * @Date 2020/4/22 14:58
 * @Version 1.0
 */
@Slf4j
public class RSAUtils {

    /** 指定key的大小 */
    private static int KEY_SIZE = 2048;

    public static void main(String[] args) throws Exception {
//        Map<String, String> retMap = generateKeyPair();
//        System.out.println(JSON.toJSONString(retMap));
//        String str = "eyJkZXNjcmlwdGlvbiI6IjIyMjIyMjIiLCJuYW1lIjoi5rWL6K+V5aWX6aSQIiwic3RhdHVzIjoxLCJzeXNTZXJ2ZXJMaXN0IjpbeyJzZXJ2ZXJOYW1lIjoiIiwic3lzdGVtTmFtZSI6IuWPjOmxvEVITSIsInVuaXQiOiIiLCJ2YWx1ZSI6IjEwMCJ9LHsic2VydmVyTmFtZSI6IiIsInN5c3RlbU5hbWUiOiLlj4zpsbxFSE0iLCJ1bml0IjoiIiwidmFsdWUiOiI1MDAifSx7InNlcnZlck5hbWUiOiIiLCJzeXN0ZW1OYW1lIjoiQ1BNU+ezu+e7nyIsInVuaXQiOiIiLCJ2YWx1ZSI6IjI4In0seyJzZXJ2ZXJOYW1lIjoiIiwic3lzdGVtTmFtZSI6IkNQTVPns7vnu58iLCJ1bml0IjoiIiwidmFsdWUiOiI5OTgifV19";
//        System.out.println(base64DecodeStr(str));
//        String pubKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxGL7PWA0wg1k7ENdg9GR7Bka6dKZH/aK8VN7IEEiORO4sTqI+1lvAPdcjDZA7Z3Ii1X5vj3NKzRQd2My3lGNiaPl8uTAFRmkJVemu2mxnYqNwh/uW3qFurvlE200wQ+su9a66FbQMAycNBzc1pEnwORRrWlVf09AyT0HkTy+HqdfNNxJa8v8EIlVDjBNPnIGlRgCfGNhEW6UjPj7gPMhk++mqZ4fKQbx0tkcuf99Iv67Rfi/oN0wqCcj7LDr639v5HhrEnBE55ifhtUqc2G8Y2cO9sPUXxd+CklNOz//zM1isLgcI6jkTkL6vkxGCDrO2UKDkZ9ugXqMIl6mERv0TwIDAQAB";
//        String encryptData = "MDc3OWU4MzY1MDlmZDM4NDI5ZGRlZTBlMjBkMjAwZTgxMTgyNDU0Yw==";
//        String priKey = "MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDEYvs9YDTCDWTs\n" +
//                "Q12D0ZHsGRrp0pkf9orxU3sgQSI5E7ixOoj7WW8A91yMNkDtnciLVfm+Pc0rNFB3\n" +
//                "YzLeUY2Jo+Xy5MAVGaQlV6a7abGdio3CH+5beoW6u+UTbTTBD6y71rroVtAwDJw0\n" +
//                "HNzWkSfA5FGtaVV/T0DJPQeRPL4ep1803Elry/wQiVUOME0+cgaVGAJ8Y2ERbpSM\n" +
//                "+PuA8yGT76apnh8pBvHS2Ry5/30i/rtF+L+g3TCoJyPssOvrf2/keGsScETnmJ+G\n" +
//                "1SpzYbxjZw72w9RfF34KSU07P//MzWKwuBwjqOROQvq+TEYIOs7ZQoORn26Beowi\n" +
//                "XqYRG/RPAgMBAAECggEAdsc/GbIUdsHPJq7f4phgX6IXixCbGJ/vDWLmd22tm0P4\n" +
//                "UwkKTKuc3cK+sPcnchAaeVu4v311mAn+GRdgbuJ4bqU4sR31p01o4EURTQzyJkzk\n" +
//                "zGKvsZh7RaPbO1Kzs4kdeka3qUrIhCc8WrCSSRxmJN5zICUzVtrCXnSRHSDWBIc6\n" +
//                "gBdN9JpTt80+uI3nNx9wzrvM1PgXDVZRgpgxwROJh+htzWeaPFFaS8wMyU6yiNyV\n" +
//                "bw7fx1Es/r/suFwwJA1H8k7YveYB/8oLNiSnGh/9mcyJowEgCoPh1V92KUtieZHC\n" +
//                "nXkOHNJEWnbEYl3J/QpXVeKmkaz/eel5zP3dTclEUQKBgQDziQ9BJoyURPBtYQA5\n" +
//                "cgqkk46zRylJKd1dlMvrkA6IxPWt4VnJQn00OwfctiyoyDbP8vkoIipg5YWdZS/K\n" +
//                "h8AGOfZRySvJiz/Hzev/UOh8dJdq1CDleMPMptQR2TwWWJUSlhbskE1u+TIXFXrT\n" +
//                "6OwChk+Cxiqs22ptP5thMcnSjQKBgQDOcCblFeEssx0RO0G5KrgCtDmM5OC78KBF\n" +
//                "Nfw78M6fEFlgvRJjYuRFa3ITGBfvmWUTxPMEqtRQ5Be7QRaqhtwMrhFxmB7Nz4OK\n" +
//                "GnxmcaxJQp1zIaz5zcxY8DsYlHIe0gismA4KCjdSek+iVNTT5dnvwOx9dCCy4PiF\n" +
//                "+PgVlfmZSwKBgQCz+DJ0s/cpTvTZ79gJm7QvwPewlsL01WJIWMCFmRSUj/D6iVEf\n" +
//                "wOnjokgCHAJOzH5tGCJ2PSFSL+uY0AEMS1tlfooAEIkyTJxanFttdy4HYuXOxWp2\n" +
//                "CdOwNgz8D6wu21F2xcG1GkKO4srYckAtv7BBgV3ax3Ub/p3clCfQIMoDtQKBgQDC\n" +
//                "4lOFnuMlXK4LL2K7WJ3AR72wyf1yzxWuYOmO+KVGupt13Og4FQqkkmttpSgrlCc8\n" +
//                "w4gcFt06xCm3KBoqwAeKnOVw1If4CXgHbzuTRqq7unyDTP5MEUFhkOBpMvKNMADq\n" +
//                "Vt2iEsTpQvhcqjMFG49jbECVqoSX+hQD/ebOEfhBAwKBgQCm2eXTfVAhxVIsfflv\n" +
//                "CZis9E810/B90aSNhecyuy0VJCe+jWYr7WB3l2y2jfZ9AhJC6lOtGI4gLr1EfeT8\n" +
//                "WNDOlhJoin1KNgUID8U6+TabZsXTpGFlIo6orXBULhI6FmvAgQDs4An4SKOGBNyl\n" +
//                "zSK5oGIIKnahgfvzMKFRroNGlg==";
//
//        System.out.println(decrypt(encryptData, priKey));
//        System.out.println(base64EncodeStr("mysys:{bcrypt}$2a$10$WsEhWoPOq8YrcGVhbkqSDenDUiy6SnyCFxadnMVd9iCTzpKel4FZm"));
//        String str = "eyJhbGciOiJIUzI1NiJ9.eyJ0ZW5hbnRUeXBlIjoiMiIsInVpZCI6ImFkbWluIiwiYWxsT3JnQ29kZSI6WyJDU09UMDAwMCIsInRlc3RvcmdwZXJtaXNzaW9uIl0sImVtcE51bSI6ImFkbWluIiwicG9zdGlvbkNvZGVzIjpbbnVsbCxudWxsXSwiaXNUZW5hbnRNYW5hZ2VyIjp0cnVlLCJuYW1lIjoi56ef5oi3566h55CG5ZGYLWFkbWluIiwibW9iaWxlIjoiMTg5MjkzMDU2OTQiLCJ0ZW5hbnRJZCI6ImdlZWsiLCJsYW5ndWFnZSI6InpoLUNOIiwiYWxsT3JnQ29kZVBhdGgiOltudWxsLCJ0ZXN0b3JncGVybWlzc2lvbiJdLCJlbWFpbCI6ImFkbWluQGdldGVjaC5jbiJ9.j9v3s_aFRLicI8c-tpRY5indWM8LzNL00ojk8qnJTMM";
//        System.out.println(base64DecodeStr(str));
//        StopWatch sw = new StopWatch("generate rsa pub/pri key.");

        String pubKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkZBi465ZfnhNtmyOM72+mNeexc60+ZzRjzOUmIrvzUBMwRbAq7xBxiJBeMlcl33fWsOPp+31c93qHPQWnlnYXPaNcL6ADlLSe72mY/euwfJ0hN+1K+kI3k3fhT2PwemJy1w6KNRS/NLjurwjTx9qFzRiazD5Bc2FWD8IcpLBPyl1Jd6ErS30dMoaymC4ByTS1f1yGZ0pF/OHG7cn5i4QWNns5a0OKO4uUJMPoi9Z5G4Kzwva/m28OTa/3XS6azXwoZTkfkNAD00yHArZN0ITa2mPGkk3P+xRV36SULtNx0Vy/UE+aWBBenVwj2R3G17SWlbtsABlSu1Lv+NMLc3nnwIDAQAB";

        String priKey = "MIIEpAIBAAKCAQEAmJT3PzBwvUgFkT3WjRtFUgjRLeUOMMEy7jro8vgRDX+Gc8EW\n" +
                "kKg3hl//YSaQvH97xEWCUZqRe8a+u3H8c879/4lNb9hNuix2L47afc9XJFBHskxR\n" +
                "uRYOyIGetZha8hHDn+bQMz7qlAw65nzb/NFHvg/YTu02bnemdrXPK6nToew3zwdu\n" +
                "G/mId5E4geV2yX9WGJ9ZGZ+rw3G8aOApvqn3FOTSyR2vZYXOevaiI9rk8GBMg8aR\n" +
                "/ahlAZ39OF6PnZwUEuG+P9a9uDUWLrmxtaYO9wc7S/Vn7ZAEZBQw+BNSIbfHI3TI\n" +
                "FWFnJg/cDg54DGKBGGOqQvTVIpzHwTDsMV+baQIDAQABAoIBACyix4GwxgpZW2eV\n" +
                "04IMDEdnVOo8K96PZjrS+Pq7HyH3wHl0bwl6bGPfCXJ+ObErCiXsv6bntM+k4H8t\n" +
                "ZVDrqNpsbD7f5D0mbJyVCc3sLe3tnkvGj9G5ZjG52Zf+LfzKvZO1jgqvySfuO/zZ\n" +
                "YfGft4EeWYUdV+MRFZ18qlJ3p/WiFTWa69bRWpOwC6cY6DvT5Rwu8tAQwlEPMV6b\n" +
                "QAvplbBmy6DUDIZ/IS7JDY17Lz1y5IMsMbLyl3K5t1QcnPp/zqrMLO1KeyC5AC/K\n" +
                "OM++l++ABHb41vwPbJPo4yElmVYI7EpIrlMdlEKgfC43Em8fhhWGa1tG9N5nLhCE\n" +
                "JjqXgtECgYEAyqlUq0KFwNFZ0oSdq7nOUwXBS9ZwpDBe/Nj2Oziy+blwj8Jr75W1\n" +
                "ww5jF7+kAakjr1ZJCA0MwNEf0Cn32ZV9rIXK5EUZPgHyp6UX4VQ1p3Y6Fbquyj9E\n" +
                "YwwS+pEvJlEMoi2Jr30pvjEhZpegguVdKJqMBQLz5Kyd6Da3nUMNqM8CgYEAwL1w\n" +
                "FarBQs05mNkqvxZduzwL8gkvUXiq/cMge4pE8tyz7Xdldb/0Qv/odb2rGdsoSqE5\n" +
                "G382SczP3iS6Vqavqt4u1jiZLHRZLD5lnIukUwTH92FZOvcCZRrUTnaVn52Txcrb\n" +
                "HjSbVWs6Nj23fwfoztY7MTfaseXx41ZQoC+sFkcCgYA3BMF3vReSwUMhY99qP4dE\n" +
                "Asv3SsBJ0tf2zPAMI9hy82UboiyrXnl5+u3sBJsB2GlXsJUjGmfb8OoyGTKwX2U+\n" +
                "8ROj5R51NxIpcSiKg9INJIugWo4ZWhO20BBW9hNW06oaXUKD4fbzK2Nl9sQcxSgF\n" +
                "Xe+lbKfJ7RLxd+lhSFLtAQKBgQCks30LVt5NOlgksDciEXfJXveKPaUMxsO/k7W3\n" +
                "PCHNMyIiI2w1IfIWKt63dnu23ZthosHNKHj4uadL2jDNiSUGK1T0xGrIHShycWOd\n" +
                "UYr7UlOaprp8c8W9Jh8UaatUOXCkjcOO3T97z+Rvo2+hgt3Dmjf8yBD/AlMghIrj\n" +
                "R7mTUwKBgQCEUy6X1GcNe+GJiftFGs2mQSwXNNnJuTfdBnJAmE6B3vOin/0a/RHt\n" +
                "C8zsFd/CawZJuHIdwY6jRteYVGTkBRLfAU1SA38aq+CL3YK6ANJe6uNgY2rkPzqz\n" +
                "ET0ChkI8SpGLNFF6b9jdJrK5VjoESW3K3Fv//DCmwgmkuT7kvNa2+Q==\n";

        String msg = "Vy0wOZd/ir3BgtBirfq/M/bA8AizvpbI10lrKyc3CMrpQsii5y1YKKXASPUF    EN53DR5fs0ubKj8a5duEpTx9a4WeVqwEEt83NDBX2eEm6Qa2q8ZdVOxlJBhx7UgDpF9wiHVBx+tNaaZBI1RsGpopHtHfB1CjqVWJVN22rgpW4MAloiaRQRTb1F0m+3FUHu5zbK98qG9Bcn0RCZr/jh2gH8fQXCWfWV8d8E/L/I9BDSVdY66rSK9+PpixaX7awNzd3g7QVQyi2wnt+JSmnvLDYYPdlfCEFTPEp996E0OlXSXgsT6zJXENOzrDj01YopEJ0ZEnz/5XOg79swqs2nhfkg==";
//        String encrypt = encrypt(msg, pubKey);

        String decrypt = decrypt(msg, priKey);
        System.out.println(decrypt);


    }
    /**
     * 生成密钥对
     */
    public static Map<String, String> generateKeyPair() throws Exception {
        /** RSA算法要求有一个可信任的随机数源 */
        SecureRandom sr = new SecureRandom();
        /** 为RSA算法创建一个KeyPairGenerator对象 */
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
        /** 利用上面的随机数据源初始化这个KeyPairGenerator对象 */
        kpg.initialize(KEY_SIZE, sr);
        /** 生成密匙对 */
        KeyPair kp = kpg.generateKeyPair();
        /** 得到公钥 */
        Key publicKey = kp.getPublic();
        byte[] publicKeyBytes = publicKey.getEncoded();
        String pub = new String(Base64.encodeBase64(publicKeyBytes),
                EncryptConstants.CHAR_ENCODING);
        /** 得到私钥 */
        Key privateKey = kp.getPrivate();
        byte[] privateKeyBytes = privateKey.getEncoded();
        String pri = new String(Base64.encodeBase64(privateKeyBytes),
                EncryptConstants.CHAR_ENCODING);

        Map<String, String> map = new HashMap<String, String>();
        map.put("publicKey", pub);
        map.put("privateKey", pri);
        RSAPublicKey rsp = (RSAPublicKey) kp.getPublic();
        BigInteger bint = rsp.getModulus();
        byte[] b = bint.toByteArray();
        byte[] deBase64Value = Base64.encodeBase64(b);
        String retValue = new String(deBase64Value);
        map.put("modulus", retValue);
        return map;
    }

    /**
     * 加密方法 source： 源数据
     */
    public static String encrypt(String source, String publicKey)
            throws Exception {
        Key key = getPublicKey(publicKey);
        /** 得到Cipher对象来实现对源数据的RSA加密 */
        Cipher cipher = Cipher.getInstance(EncryptConstants.ALGORITHM_RSA_ECB);
        cipher.init(Cipher.ENCRYPT_MODE, key);
        byte[] b = source.getBytes();
        /** 执行加密操作 */
        byte[] b1 = cipher.doFinal(b);
        return new String(Base64.encodeBase64(b1),
                EncryptConstants.CHAR_ENCODING);
    }

    /**
     * 解密算法 cryptograph:密文
     */
    public static String decrypt(String cryptoGraph, String privateKey)
            throws Exception {
        Key key = getPrivateKey(privateKey);
        /** 得到Cipher对象对已用公钥加密的数据进行RSA解密 */
        Cipher cipher = Cipher.getInstance(EncryptConstants.ALGORITHM_RSA_ECB);
        cipher.init(Cipher.DECRYPT_MODE, key);
        byte[] b1 = Base64.decodeBase64(cryptoGraph.getBytes());
        /** 执行解密操作 */
        byte[] b = cipher.doFinal(b1);
        return new String(b);
    }

    /**
     * 得到公钥
     *
     * @param key
     *            密钥字符串（经过base64编码）
     * @throws Exception
     */
    public static PublicKey getPublicKey(String key) throws Exception {
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(
                Base64.decodeBase64(key.getBytes()));
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PublicKey publicKey = keyFactory.generatePublic(keySpec);
        return publicKey;
    }

    /**
     * 得到私钥
     *
     * @param key
     *            密钥字符串（经过base64编码）
     * @throws Exception
     */
    public static PrivateKey getPrivateKey(String key) throws Exception {
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(
                Base64.decodeBase64(key.getBytes()));
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
        return privateKey;
    }

    public static String sign(String data, String sign_pri_key) {
        String charset = EncryptConstants.CHAR_ENCODING;
        try {
            PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(
                    Base64.decodeBase64(sign_pri_key.getBytes()));
            KeyFactory keyFac = KeyFactory.getInstance("RSA");
            PrivateKey priKey = keyFac.generatePrivate(priPKCS8);

            Signature signature = Signature.getInstance("SHA256WithRSA");

            signature.initSign(priKey);
            signature.update(data.getBytes(charset));

            byte[] signed = signature.sign();

            return new String(Base64.encodeBase64(signed));
        } catch (Exception e) {
            log.error("", e);
        }

        return null;
    }

    public static boolean checkSign(String content, String sign, String publicKey)
    {
        try
        {
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            byte[] encodedKey = Base64.decode2(publicKey);
            PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));


            java.security.Signature signature = java.security.Signature.getInstance("SHA256WithRSA");

            signature.initVerify(pubKey);
            signature.update( content.getBytes("utf-8") );

            boolean bverify = signature.verify( Base64.decode2(sign) );
            return bverify;

        }
        catch (Exception e)
        {
            log.error(e.getMessage(), e);
        }

        return false;
    }

    public static String base64EncodeStr(String str) {
        if (StringUtils.isEmpty(str)) {
            return str;
        }
        return new String(org.apache.commons.codec.binary.Base64.encodeBase64(str.getBytes()));
    }

    public static String base64DecodeStr(String str) {
        if (StringUtils.isEmpty(str)) {
            return str;
        }
        return new String(org.apache.commons.codec.binary.Base64.decodeBase64(str.getBytes()));
    }

}
